#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

#include "task.hpp"
#define gnum 5
using namespace std;

Task t;

class EndPoint
{
public:
    pid_t _child_id;
    int   _write_fd;
public:
    EndPoint(int id, int fd) : _child_id(id), _write_fd(fd)
    {
    }
    ~EndPoint()
    {
    }
};

// 子进程要执行这个方法
void WaitCommand()
{
    while (true)
    {
        int command = 0;
        int n = read(0, &command, sizeof(int));
        cout << command << endl;
        if (n == sizeof(int))
        {
            t.Execute(command);
        }
        else if (n == 0)
        {
            break;
        }
        else
        {
            break;
        }
    }
}

// 父进程写，子进程读
void createProcesses(vector<EndPoint> *end_points)
{
    for (int i = 0; i < gnum; i++)
    {
        // 1.1创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);

        // 1.2创建进程
        pid_t id = fork();

        // 子进程的代码：
        if (id == 0)
        {
            // 1.3关闭不需要的fd
            close(pipefd[1]);

            // 1.3.1输入重定向
            // 之后只要在标准输入里读就可以了
            dup2(pipefd[0], 0);
            // 1.3.2子进程等待获取命令
            WaitCommand();

            close(pipefd[0]);
            exit(0);
        }

        // 父进程的代码：
        // 1.3关闭不需要的fd
        close(pipefd[0]);

        // 1.4将新的子进程和他的管道写端构建对象。
        end_points->push_back(EndPoint(id, pipefd[1]));
        cout << "pid:" << id << "fd:" << pipefd[1] << endl;
    }
}

int Menu()
{
    cout << "请选择对应操作" <<endl;
    cout << "0、打印日志数据" <<endl;
    cout << "1、打印mysql数据" <<endl;
    cout << "2、打印网络库数据" <<endl;
    cout << "3、退出" << endl;
    int n;
    cin >> n;
    return n;
}

void ctrlProcess(vector<EndPoint>& end_points)
{
    while (true)
    {
        // 1.选择一个命令:
        int command = Menu();
        if(command == 3) break;

        // 2.选择一个子进程
        int index = rand() % end_points.size();

        // 3.下发任务
        write(end_points[index]._write_fd, &command, sizeof(command));
        sleep(1);
    }
}

void waitProcess(vector<EndPoint>& end_points)
{
    // 1、关闭父进程所有写端，写端关闭，子进程读不到数据n==0的时候就会退出
    for(int i = 0;i < end_points.size();i++)
    {
        close(end_points[i]._write_fd);
    }
    cout << "父进程已经关闭了所有子进程了" << endl;
    sleep(10);

    // 2、父进程还要负责回收子进程的僵尸状态
    for(const auto& ep : end_points)
    {
        waitpid(ep._child_id,nullptr,0);
    }
    sleep(10);
}

int main()
{
    // 1.先要构建控制结构，父进程写入，子进程读取
    vector<EndPoint> end_points;
    createProcesses(&end_points);

    // 2.
    ctrlProcess(end_points);

    // 3.
    waitProcess(end_points);

    return 0;
}